﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Reflection;
using Equation.Enterprise.Utilities.DesignByContract;

namespace Equation.Enterprise.Framework.Domain.Data
{
    public class DbContextManager
    {
        public static object syncLock = new object();
        public static readonly string DefaultStorageKey = "dbcontextmanager.storagekey";
        private static Dictionary<string, IDbContextBuilder> dbContextBuilders = new Dictionary<string,IDbContextBuilder>();
        private static Dictionary<string, IDbContextStorage> dbContextStorages = new Dictionary<string, IDbContextStorage>();

        public static DbContext Current
        {
            get { return CurrentFor(DefaultStorageKey); }
        }

        public static DbContext CurrentFor(string key)
        {
            Check.Require(!string.IsNullOrEmpty(key));

            DbContext dbContext = null;

            lock(syncLock)
            {
                if (!dbContextBuilders.ContainsKey(key))
                    throw new ApplicationException("No DbContextBuilder with key " + key + " exist");

                dbContext = dbContextStorages[key].Context;
                if (dbContext == null)
                {
                    dbContext = dbContextBuilders[key].Build();
                    dbContextStorages[key].Context = dbContext;
                }
            }

            return dbContext;
        }

        public static void Init(IDbContextStorage storage, string connectionStringNames, string[] mappingAssemblyNames, bool lazyLoadEnabled=true)
        {
            Check.Require(!string.IsNullOrEmpty(connectionStringNames));
            Check.Require(mappingAssemblyNames != null && mappingAssemblyNames.Length>0);
            Check.Require(storage!=null);
            Check.Require(dbContextStorages.ContainsKey(storage.StorageKey));

            AddContextBuilder(storage.StorageKey, connectionStringNames, mappingAssemblyNames, lazyLoadEnabled);

            dbContextStorages.Add(storage.StorageKey, storage);
        }

        private static void AddContextBuilder(string storageKey, string connectionStringName, string[] mappingAssemblies, bool lazyLoadEnabled)
        {
            lock(syncLock)
                dbContextBuilders.Add(storageKey, new DbContextBuilder(connectionStringName, mappingAssemblies, lazyLoadEnabled));
        }

        public static void Init(IDbContextStorage storage, string connectionStringNames, Assembly[] mappingAssemblyNames, bool lazyLoadEnabled = true)
        {
            Check.Require(!string.IsNullOrEmpty(connectionStringNames));
            Check.Require(mappingAssemblyNames != null && mappingAssemblyNames.Length > 0);
            Check.Require(storage != null);
            Check.Require(!dbContextStorages.ContainsKey(storage.StorageKey));

            AddContextBuilder(storage.StorageKey, connectionStringNames, mappingAssemblyNames, lazyLoadEnabled);

            dbContextStorages.Add(storage.StorageKey, storage);
        }

        private static void AddContextBuilder(string storageKey, string connectionStringName, Assembly[] mappingAssemblies, bool lazyLoadEnabled)
        {
            lock (syncLock)
                dbContextBuilders.Add(storageKey, new DbContextBuilder(connectionStringName, mappingAssemblies, lazyLoadEnabled));
        }
    }
}
